<h1 id="u语言设计文档">U语言设计文档</h1>
<h2 id="前置描述">前置描述</h2>
<p>本文档描述了U语言设计目标，用VS Code + 扩展（Markdown Preview
Enhanced）编写，随着编译器开发的进展，会逐渐完善；本文档往往早于编译器实现
下文格式[]中的表示可选</p>
<h4 id="最后更新时间-2023919">最后更新时间 ： 2023/9/19</h4>
<hr />
<h2 id="关键字">关键字</h2>
<table>
<thead>
<tr class="header">
<th>文本</th>
<th>语义</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>func</td>
<td>声明一个函数</td>
</tr>
<tr class="even">
<td>var</td>
<td>声明一个变量</td>
</tr>
<tr class="odd">
<td>const</td>
<td>声明一个常量</td>
</tr>
<tr class="even">
<td>if</td>
<td>声明一个分支</td>
</tr>
<tr class="odd">
<td>else</td>
<td>声明不匹配分支</td>
</tr>
<tr class="even">
<td>for</td>
<td>声明一个循环</td>
</tr>
<tr class="odd">
<td>break</td>
<td>结束循环</td>
</tr>
<tr class="even">
<td>continue</td>
<td>结束本次循环</td>
</tr>
<tr class="odd">
<td>goto</td>
<td>跳转到指定地址</td>
</tr>
<tr class="even">
<td>interface</td>
<td>声明一个接口</td>
</tr>
<tr class="odd">
<td>struct</td>
<td>声明一个结构体</td>
</tr>
<tr class="even">
<td>switch</td>
<td>声明选择分支</td>
</tr>
<tr class="odd">
<td>case</td>
<td>比较相等为真</td>
</tr>
<tr class="even">
<td>default</td>
<td>声明未匹配分支</td>
</tr>
<tr class="odd">
<td>method</td>
<td>声明一个方法</td>
</tr>
<tr class="even">
<td>package</td>
<td>声明源文件所属的包</td>
</tr>
<tr class="odd">
<td>import</td>
<td>导入包</td>
</tr>
<tr class="even">
<td>autofree</td>
<td>声明一个自动释放块</td>
</tr>
<tr class="odd">
<td>nil</td>
<td>指针类型的零值</td>
</tr>
<tr class="even">
<td>enum</td>
<td>声明枚举类型</td>
</tr>
<tr class="odd">
<td>true</td>
<td>真</td>
</tr>
<tr class="even">
<td>false</td>
<td>假</td>
</tr>
</tbody>
</table>
<h2 id="运算符">运算符</h2>
<table>
<thead>
<tr class="header">
<th>符号</th>
<th>语义</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>+</td>
<td>相加</td>
</tr>
<tr class="even">
<td>-</td>
<td>相减</td>
</tr>
<tr class="odd">
<td>*</td>
<td>相乘</td>
</tr>
<tr class="even">
<td>/</td>
<td>相除</td>
</tr>
<tr class="odd">
<td>%</td>
<td>取余数</td>
</tr>
<tr class="even">
<td>&lt;</td>
<td>比较是否小于</td>
</tr>
<tr class="odd">
<td>&gt;</td>
<td>比较是否大于</td>
</tr>
<tr class="even">
<td>!=</td>
<td>比较是否不相等</td>
</tr>
<tr class="odd">
<td>==</td>
<td>比较是否相等</td>
</tr>
<tr class="even">
<td>++</td>
<td>加1</td>
</tr>
<tr class="odd">
<td>–</td>
<td>减1</td>
</tr>
<tr class="even">
<td>||</td>
<td>逻辑或</td>
</tr>
<tr class="odd">
<td>&amp;&amp;</td>
<td>逻辑与</td>
</tr>
<tr class="even">
<td>^</td>
<td>异或</td>
</tr>
<tr class="odd">
<td>and</td>
<td>位与</td>
</tr>
<tr class="even">
<td>|</td>
<td>位或</td>
</tr>
<tr class="odd">
<td>&amp;</td>
<td>取地址</td>
</tr>
<tr class="even">
<td>@</td>
<td>解引用</td>
</tr>
</tbody>
</table>
<p>对于 + 、 - 、* 、 / 可以统称为四则运算</p>
<p>对于 != 、 == 可以统称为判等运算</p>
<p>对于 &lt; 、&gt; 可以统称为比大小运算</p>
<p>对于 || 、&amp;&amp; 可以统称为逻辑运算</p>
<p>对于 ++、-- &amp;、@ 要求右边有一个操作数</p>
<p>对于@ 要求右边必须是指针类型</p>
<p>对于 四则运算、 判等运算、比大小运算、 逻辑运算
要求左边和右边各有一个操作数，操作数的类型必须相同</p>
<h2 id="优先级">优先级</h2>
<table>
<thead>
<tr class="header">
<th>权重</th>
<th>运算类型</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>10</td>
<td>括号</td>
</tr>
<tr class="even">
<td>9</td>
<td>乘除或取余</td>
</tr>
<tr class="odd">
<td>8</td>
<td>加减运算</td>
</tr>
<tr class="even">
<td>7</td>
<td>比大小运算</td>
</tr>
<tr class="odd">
<td>6</td>
<td>判等运算</td>
</tr>
<tr class="even">
<td>5</td>
<td>位与运算</td>
</tr>
<tr class="odd">
<td>4</td>
<td>异或运算</td>
</tr>
<tr class="even">
<td>3</td>
<td>位或运算</td>
</tr>
<tr class="odd">
<td>2</td>
<td>逻辑与运算</td>
</tr>
<tr class="even">
<td>1</td>
<td>逻辑或运算</td>
</tr>
</tbody>
</table>
<p>权重越高，优先级越高
如果相同权重的运算符出现在同一个表达式，左边的比右边的优先级高</p>
<h2 id="术语含义">术语含义</h2>
<h3 id="代码块">代码块</h3>
<p>除非明确例外，一对左大括号和右大括号和在之间的内容组成代码块
例外：</p>
<ul>
<li>一个case和另一个case，行数更小的一行与之间的内容组成代码块</li>
<li>一个case和一个default，行数更小的一行与之间的内容组成代码块</li>
<li>一个case或default和一个右大括号，同时case或default的行数更小，case或default和右大括号与之间的内容组成代码块</li>
<li>整个代码文件是一个代码块</li>
</ul>
<p>代码块可以嵌套代码块，被嵌套的称为子代码块，没被嵌套的称为上级代码块
子代码块在上级代码块之间，但子代码块和上级代码块不是同一个代码块</p>
<p>代码块如果有左大括号必须出现在同一行末尾</p>
<h3 id="有语义的符号">有语义的符号</h3>
<p>有语义的符号指运算符、//、/* 、*/、” 、&amp; 、@</p>
<h3 id="预先声明的标识符">预先声明的标识符</h3>
<p>预先声明的标识符包括：以及所有的<a href="#内置类型">内置类型</a>
和所有的<a href="#内置函数">内置函数</a></p>
<h3 id="标识符">标识符</h3>
<p>每个程序实体（例如变量）有一个名字，被称为标识符，或符号</p>
<p>标识符的第一个字符不能为数字 标识符不能包含空格、有语义的符号
标识符不能是关键字 在同一个代码块不允许符号重名</p>
<h3 id="作用域">作用域</h3>
<p>一个标识符有限定的可使用范围，称为作用域
作用域的范围无特别规定在声明的代码块内
在一个代码块嵌套的子代码块可以重新声明标识符，当子代码块声明的标识符在子代码块内时，它表示子代码块声明所声明的实体</p>
<h3 id="名称和类型的组合">名称和类型的组合</h3>
<p>对于格式为 名称 类型 的代码，本规范用术语名称和类型的组合统称
对于出现在函数声明的参数列表的名称和类型的组合，称为函数参数
对于出现在结构体声明的名称和类型的组合，称为结构体的字段，简称字段</p>
<h3 id="词法分析结果开头">词法分析结果开头</h3>
<p>词法分析结果开头 是一行除了空格或制表符 第一个单词</p>
<h3 id="未定义的">未定义的</h3>
<p>含义是没有规则定义应该会出现或不出现什么情况</p>
<h3 id="布尔值">布尔值</h3>
<p>true和false统称为布尔值</p>
<h3 id="n个语句">N个语句</h3>
<p>N个语句是在0或多个以空行分隔的<a href="#语句">语句</a></p>
<h3 id="导入包与被导入包">导入包与被导入包</h3>
<p>术语导入包与术语被导入包是一样的含义，含义如下：</p>
<p>如果包p导入包，则称包q为导入包或被导入包</p>
<hr />
<h2 id="注释">注释</h2>
<h3 id="单行注释">单行注释</h3>
<p>单行注释是一行中 // 连同后面的内容</p>
<h3 id="多行注释">多行注释</h3>
<p>多行注释用 /* 开头 */结束，开头和结束还有之间的内容为多行注释</p>
<p>/* 开头和 */结束必须在词法分析结果开头</p>
<hr />
<h2 id="类型">类型</h2>
<p>类型赋予一段连续的内存特定于这些值的操作和方法</p>
<h3 id="内置类型">内置类型</h3>
<table>
<thead>
<tr class="header">
<th>类型</th>
<th>属性</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>int</td>
<td>8字节有符号整数</td>
</tr>
<tr class="even">
<td>float</td>
<td>4字节浮点数</td>
</tr>
<tr class="odd">
<td>bool</td>
<td>布尔类型</td>
</tr>
<tr class="even">
<td>string</td>
<td>字符串</td>
</tr>
<tr class="odd">
<td>unsafe__Pointer</td>
<td>无类型指针</td>
</tr>
<tr class="even">
<td>any</td>
<td>空接口</td>
</tr>
</tbody>
</table>
<h3 id="布尔类型">布尔类型</h3>
<p>布尔类型的值只能是布尔值 布尔类型只能进行判等运算或逻辑运算</p>
<h3 id="字符串类型">字符串类型</h3>
<p>在 " 之间的内容和左边的 " 以及右边的 " 定义字符串</p>
<p>" 前有一个\转义为字符串的一部分</p>
<h3 id="指针类型">指针类型</h3>
<p>指针的零值是nil</p>
<p>指针只允许判等运算</p>
<h4 id="有类型指针">有类型指针</h4>
<p>对于类型T,&amp;T表示T的指针类型</p>
<p>对于类型为T的操作数x，&amp;x产生类型为&amp;T的指针，指针指向的内存地址是x的内存地址</p>
<p>对于类型为&amp;T的指针x，<span class="citation"
data-cites="x表示指针指向的T类型数据">@x表示指针指向的T类型数据</span></p>
<h4 id="无类型指针">无类型指针</h4>
<p>unsafe__Pointer是没有类型的指针，不能解引用。</p>
<h3 id="结构体类型">结构体类型</h3>
<p>结构体由一系列字段组成，结构体的所有字段称为结构体的字段集
结构体可以没有字段，称为空结构体</p>
<p>结构体的声明格式为 struct 结构体名[<a
href="#类型参数列表">泛型参数列表</a>]{ 换行 [字段列表]}
这又被称为结构体声明语句</p>
<p>字段列表的语法是递归定义的，语法形式为： 字段[换行 字段列表]</p>
<p>字段行数越小，就是结构体第n个字段中的n越小，n最小为1</p>
<p>示例</p>
<pre><code>struct s{
    len1 int
    len2 int
}</code></pre>
<p>s是一个结构体,第一个字段是名字是len1，类型是int,第二个字段是名字是len2，类型是int。</p>
<p>对于结构体声明的所有方法，声明形式参见<a
href="#方法">方法</a>，称为结构体的方法集</p>
<h3 id="接口类型">接口类型</h3>
<p>接口声明一组约束，接口类型只能用于<a
href="#类型参数">类型参数</a>。</p>
<p>接口类型的语法形式是：</p>
<pre><code>interface name{ 
    [约束条件]
}</code></pre>
<p>约束条件可以有多个，一行只能有一个</p>
<p>约束条件的语法形式是： Type Value</p>
<p>Type 必须是 field,method之一</p>
<p>当Type是
field时，value必须是一个标识符，这个约束的语义是<strong>满足接口的类型，必须有名为value的字段</strong></p>
<p>当Type是
method时，value必须是<strong>函数声明去掉最前面的func和最后面的代码块</strong>，这个约束的语义是<strong>满足接口的类型，必须有value这个方法</strong></p>
<p>示例：</p>
<pre><code>interface f{
    field s
    method f()
}</code></pre>
<p>满足上面的f接口的类型必须有一个名叫s的字段，和一个名叫f无参数无返回值的方法</p>
<h3 id="数组类型">数组类型</h3>
<p>对于 类型 T [expr]T 表示expr表示的expr个连续的T类型数据</p>
<p>这里的[expr]不是可选。</p>
<p>expr必须是表示整数的表达式</p>
<p>T 是数组的元素类型，expr表示的整数是数组类型的长度</p>
<p>示例：[3]int表示3个连续的int类型数据</p>
<h3 id="切片类型">切片类型</h3>
<p>对于 类型 T []T 表示的不定长个连续的T类型数据</p>
<p>这里的[]不是可选。</p>
<p>expr必须是表示整数的表达式</p>
<p>T 是切片的元素类型</p>
<h3 id="连续类型">连续类型</h3>
<p>切片类型和数组类型，统称为连续类型</p>
<h3 id="枚举类型">枚举类型</h3>
<p>枚举类型的声明为</p>
<pre><code>enum 类型名 {
    枚举值
}</code></pre>
<p>这又被称为枚举声明语句</p>
<p>枚举值可以有多个，但一行只能有一个枚举值</p>
<p>枚举值是一个标识符</p>
<p>一个枚举类型的所有枚举值称为这个类型的枚举集</p>
<p>设枚举类型为 E , 枚举值为V，使用V的语法形式是E.V</p>
<h2 id="类型转换">类型转换</h2>
<p>设转换类型为 T , 被转化值为V</p>
<p>语法形式为：T(V) 表示把V的类型转换为T</p>
<p>限制：只允许int类型和float相互转换，或任意指针类型转换为unsafe__Pointer</p>
<p>unsafe__Pointer是一个特别的例外，这个类型可以转换为任意类型的指针类型，转换使用<a
href="#unsafe__convert">unsafe__Convert</a></p>
<h2 id="类型相等">类型相等</h2>
<p>符合下列规则至少一个的两个值的类型相等</p>
<ul>
<li>两个一样的类型相等 （示例：int类型1和int类型1，<a
href="#类型相等">类型相等</a>）</li>
<li>指针类型和nil相等 （示例：unsafe__Pointer类型的1和nil，<a
href="#类型相等">类型相等</a>）</li>
<li>接口类型和实现这个接口的类型相等</li>
</ul>
<hr />
<h2 id="选择器">选择器</h2>
<p>选择器的语法形式是 x.y，表示从x选择y x称为左值，y称为右值
左值和右值必须是标识符或&amp;标识符或@标识符或选择器</p>
<p>以下选择器是有错误的</p>
<ul>
<li>如果x的类型是结构体，同时x的字段集和方法集中都没有y</li>
<li>如果x是导入的包名，同时x导出的标识符没有y</li>
<li>如果x不是结构体、包名、枚举类型之一</li>
<li>如果x是枚举类型，x的枚举集里没有y</li>
</ul>
<hr />
<h2 id="表达式">表达式</h2>
<p>能表达值的就是一个表达式</p>
<h3 id="对象表达式">对象表达式</h3>
<p>符合下列列出之一的是对象表达式：</p>
<ul>
<li>如果是整数，表示这个整数，例如1表示整数1</li>
<li>如果是浮点数，表示这个浮点数，例如1.0表示浮点数1.0</li>
<li>如果是字符串，表示这个字符串，例如”s”表示一个字符s，“ss”表示两个字符ss</li>
<li>如果是nil,表示nil</li>
<li>如果是@标识符，表示标识符的地址，例如@x表示x指向内存地址的值</li>
<li>如果是&amp;标识符，表示获取标识符的地址，例如&amp;x表示获取x的地址</li>
</ul>
<h3 id="运算表达式">运算表达式</h3>
<p>运算表达式由运算符和操作数组成 操作数是一个表达式</p>
<p>示例： 1+2 是一个表示3的运算表达式 1+2+3 是一个表示6的运算表达式</p>
<h3 id="类型转换表达式">类型转换表达式</h3>
<p>类型转换表达式参见<a href="#类型转换">类型转换</a></p>
<h3 id="函数调用表达式">函数调用表达式</h3>
<p>当<a
href="#函数调用">函数调用</a>有返回值时，这是一个函数调用表达式</p>
<h3 id="方法调用表达式">方法调用表达式</h3>
<p>当<a
href="#方法调用">方法调用</a>有返回值时，这是一个方法调用表达式</p>
<h3 id="索引表达式">索引表达式</h3>
<p>对于形如 V[N] 的表达式，称为索引表达式</p>
<p>V必须是表达式，N必须表示整数的表达式</p>
<p>如果V是连续类型,V的元素类型为T，V[N]表示的内存地址等于
unsafe__Add(v[0],unsafe__Sizeof(T)*N)</p>
<p>公式表示为 v[0]的地址+T的大小*N</p>
<p><strong>如果V是一个长度为L连续类型,N大于L,会发生的行为未定义</strong></p>
<h3 id="解引用表达式">解引用表达式</h3>
<p>对于@(X)，表示X指向内存地址的内存，称为解引用表达式。</p>
<p>X的必须是有类型指针</p>
<p>如果X是选择器，例如下列代码</p>
<pre class="u"><code>package main

struct p{
    ptr *int
}

func main(){
    var p1 &amp;p
}</code></pre>
<p><span class="citation"
data-cites="p1.ptr表示解引用p1这个指针">@p1.ptr表示解引用p1这个指针</span>，再访问@p1的ptr字段</p>
<p>@(p1.ptr)表示解引用p1.ptr这个指针</p>
<h3 id="结构体字面量表达式">结构体字面量表达式</h3>
<p>对于语法形式为 T{[值列表]} 称为结构体字面量表达式</p>
<p>值列表的语法形式是递归定义的，是：值[,值列表]</p>
<p>在值列表中越靠前，就是值列表第n个数据的n越小，n最小为1</p>
<p>T必须是结构体类型，值列表的所有值必须是表达式，且第n个值表达数据的类型与T的第n个字段的类型必须相等。</p>
<p>结构体字面量表达式的表达的是一个结构体,语义如下列出:</p>
<ol type="1">
<li>产生一个类型为T的结构体S</li>
<li>将所有的值分配给S,分配规则是S的第n个字段=第n个值</li>
<li>表达的是这个结构体</li>
</ol>
<p>示例</p>
<pre><code>package main
struct f{
    l int
    p int
}

func main(){
    var g f =f{1}
}</code></pre>
<p>f{1}
是一个结构体字面量表达式，表达的是一个类型为f的结构体，这个结构体的l字段被设置为1。</p>
<hr />
<h2 id="语句">语句</h2>
<h3 id="声明语句">声明语句</h3>
<h4 id="变量声明语句">变量声明语句</h4>
<p>变量的声明格式为 var 变量名 T [= 值]</p>
<p>变量名表示声明时指定的类型T的值的保存地址的别名</p>
<p>在同一个代码块的变量不允许重名</p>
<p>在函数外的变量是全局变量</p>
<p>在函数内的变量不允许使用在声明之前</p>
<p>值必须是一个表达式，且表达的值类型必须与类型T<a
href="#类型相等">类型相等</a></p>
<p>为了实现自动释放块，变量名开头不能是generate</p>
<h4 id="常量声明语句">常量声明语句</h4>
<p>变量的声明格式为 const 常量名 T = 值</p>
<p>常量是必须声明时赋值的，之后常量的值是不可修改的</p>
<p>值必须是一个表达式，且表达的值类型必须与类型T<a
href="#类型相等">类型相等</a></p>
<p>为了实现自动释放块，常量名开头不能是generate</p>
<h4 id="结构体声明语句">结构体声明语句</h4>
<p>参见 <a href="#结构体类型">结构体类型</a></p>
<h4 id="枚举声明语句">枚举声明语句</h4>
<p>参见 <a href="#枚举类型">枚举类型</a></p>
<h4 id="函数声明语句">函数声明语句</h4>
<p>参见 <a href="#函数声明">函数声明</a></p>
<h4 id="方法声明语句">方法声明语句</h4>
<p>参见 <a href="#方法">方法</a></p>
<h3 id="赋值语句">赋值语句</h3>
<p>赋值语句的格式是：目的操作数=源操作数</p>
<p>目的操作数和源操作数必须是表达式</p>
<p>赋值语句的语义是将源操作数赋值给目的操作数</p>
<p>要求目的操作数和源操作数的必须<a href="#类型相等">类型相等</a></p>
<h3 id="自操作语句">自操作语句</h3>
<p>包含 ++ 或 –
运算符的是自操作语句，这类语句必须单独一行，for的结束语句是唯一例外</p>
<p>下个示例是语法正确的： i++</p>
<p>下列示例是语法错误的：</p>
<p>i=i++</p>
<p>i++ + i</p>
<p>自操作语句是特别的赋值语句</p>
<p>i++ 等价于 i=i+1</p>
<p>i-- 等价于 i=i-1</p>
<h3 id="分支语句">分支语句</h3>
<h4 id="布尔表达式">布尔表达式</h4>
<p>布尔表达式是表达的值的类型是布尔类型的表达式</p>
<h4 id="if语句和else语句">if语句和else语句</h4>
<p>if语句的简单格式为 if 布尔表达式 { 换行 [<a
href="#n个语句">N个语句</a>] 换行 }</p>
<p>else语句的简单格式为 else {换行 [<a href="#n个语句">N个语句</a>]
换行} if语句和else的组合形式为 else if 布尔表达式 {换行 [<a
href="#n个语句">N个语句</a>] 换行}</p>
<p>if语句根据布尔表达式的值选择两个分支的其中一个执行。</p>
<p>如果表达式表达true，则执行if代码块内的分支，否则如果存在else语句，则执行else语句内的分支。</p>
<p>if或else还是两者组合都必须将if 或 else 或 else if
放在词法分析结果开头</p>
<h4 id="switch和case语句">switch和case语句</h4>
<p>switch语句与case语句的使用格式为 switch 表达式 {case 值: 换行 [<a
href="#n个语句">N个语句</a>] 换行}</p>
<p>switch语句和case语句一起决定根据表达式的不同值选择执行不同的分支</p>
<p>switch语句可以有最多一个 default语句 使用格式为 switch 表达式
{[default : 换行 [<a href="#n个语句">N个语句</a>] 换行] [case 值: 换行
[<a href="#n个语句">N个语句</a>] 换行]}</p>
<h3 id="循环语句">循环语句</h3>
<h4 id="for语句">for语句</h4>
<p>for语句可以重复执行一个代码块</p>
<p>for语句的典型格式为 for 初始化语句;条件表达式;结束语句{换行 [<a
href="#n个语句">N个语句</a>] 换行}</p>
<p>for语句的条件表达式为空表示为真
for语句的初始化语句、条件表达式、末尾语句都可以为空</p>
<p>for语句的初始化语句如果不为空必须是变量声明语句
for语句的条件表达式如果不为空必须表示布尔值
for语句的结束语句如果不为空必须是赋值语句或自操作语句</p>
<p>for语句的语义是：</p>
<p>1、判断条件表达式是否为真，如果为真，执行2，否则结束循环</p>
<p>2、执行循环体</p>
<p>3、执行结束语句</p>
<p>4、执行1</p>
<h3 id="跳转语句">跳转语句</h3>
<h4 id="break语句">break语句</h4>
<p>break语句可以结束for语句的执行或跳出switch代码块
break语句只能在for代码块或case代码块内出现</p>
<h4 id="continue语句">continue语句</h4>
<p>continue语句可以结束for语句的循环体的执行
continue语句只能在for代码块内出现</p>
<h4 id="goto语句">goto语句</h4>
<p>goto语句的使用格式是 goto 标签</p>
<p>goto语句的语义是跳转到标签指定的位置
goto语句跳转的标签必须和goto语句在同一函数内</p>
<h4 id="return语句">return语句</h4>
<p>return语句语义是从一个函数内返回</p>
<p>return语句必须出现在函数内 return语句后的值必须和函数声明的返回值<a
href="#类型相等">类型相等</a></p>
<hr />
<h2 id="函数">函数</h2>
<h3 id="函数参数">函数参数</h3>
<p>函数参数的语法形式是：I T</p>
<p>I是标识符，T是类型</p>
<h3 id="参数列表">参数列表</h3>
<p>参数列表的语法是递归定义的，语法形式是： 函数参数[, 参数列表]</p>
<h3 id="函数声明">函数声明</h3>
<p>函数声明格式为 func 函数名(<a href="#参数列表">参数列表</a>) [返回值]
{换行 [<a href="#n个语句">N个语句</a>] 换行} 这又被称为函数声明语句</p>
<p>参数列表为空的函数称为无参函数，否则称为有参函数
函数定义的左大括号必须在函数声明的同一行末尾
函数声明同时的代码块称为函数体</p>
<p>为了实现自动释放块，函数名结尾不能是_mempool</p>
<p><strong>函数参数是函数内的局部变量</strong></p>
<h3 id="传参列表">传参列表</h3>
<p>传参列表语法是递归定义的，语法形式是： 传参[, 传参列表] 传参必须是<a
href="#表达式">表达式</a></p>
<h3 id="函数调用">函数调用</h3>
<p>函数调用的格式为 函数名[<a href="#类型参数列表">泛型参数列表</a>](<a
href="#传参列表">传参列表</a>)</p>
<p>对于无参函数，传参列表不得非空
对于有参函数，传参列表第n个传参的类型应该和函数声明时参数列表第n个参数的<a
href="#类型相等">类型相等</a></p>
<h3 id="主函数">主函数</h3>
<p>主函数是一个命名为main的函数，无参数无返回值
不得使用main()调用主函数</p>
<p>只有main包可以有main函数，其他包不能有main函数</p>
<p>程序执行是调用main包的init函数，然后调用main函数</p>
<p>main包的init函数会调用导入包的init函数</p>
<h3 id="方法">方法</h3>
<p>对于类型T,T不是内置类型</p>
<p>method methodName[<a href="#类型参数列表">泛型参数列表</a>](<a
href="#参数列表">参数列表</a>)[返回值] {换行 [<a
href="#n个语句">N个语句</a>] 换行} 声明一个类型T的方法
这又被称为方法声明语句</p>
<p>在没有<a href="#类型参数列表">泛型参数列表</a>时这相当于 func
method__T__methodName(<a href="#参数列表">参数列表</a>)[返回值] {换行
[<a href="#n个语句">N个语句</a>] 换行}</p>
<p>方法的第一个参数类型必须是 类型T，或类型T的指针</p>
<p>方法声明同时的代码块也称为函数体</p>
<p>为了实现自动释放块，方法名结尾不能是_mempool</p>
<h3 id="方法调用">方法调用</h3>
<p>设V为T类型的变量或常量,F为T类型的方法 方法调用的格式为 V.F(<a
href="#传参列表">传参列表</a>)</p>
<p>这相当于 method__T__methodName(<a href="#传参列表">传参列表</a>)</p>
<hr />
<h2 id="内置函数">内置函数</h2>
<h3 id="printf">printf</h3>
<p>printf
接收至少一个参数，第一个参数必须是字符串，语义是将内容按指定的格式输出到标准输出</p>
<h3 id="malloc">malloc</h3>
<p>malloc 接收一个参数，参数必须是当前<a
href="#作用域">作用域</a>拥有的类型T，语义是分配大小为类型T的大小的连续内存，返回的是&amp;T</p>
<h3 id="free">free</h3>
<p>free 接收一个参数，参数必须是指针类型&amp;T，语义是释放由<a
href="#malloc">malloc</a>或<a
href="#mallocsize">mallocSize</a>分配的连续内存</p>
<h3 id="unsafe__add">unsafe__Add</h3>
<p>unsafe__Add
接收两个参数，返回一个unsafe__Pointer类型的指针，第一个参数类型必须是指针，第二个参数必须是表达整数的表达式</p>
<p>语义是将第一个参数的指针地址加第二个参数的整数的和，作为一个unsafe__Pointer类型的指针返回</p>
<p>例如：</p>
<p>unsafe__Add(p,4)</p>
<p>如果p的值是x,则返回的是unsafe__Pointer类型的x+4</p>
<h3 id="unsafe__convert">unsafe__Convert</h3>
<p>unsafe__Convert
接收两个参数，返回一个类型为第二个参数的指针，第一个参数类型必须是指针，第二个参数必须是指针类型</p>
<p>语义是将第一个参数转换为类型为第二个参数的指针，并返回</p>
<p>例如：</p>
<p>unsafe__Convert(p,&amp;int)</p>
<p>语义是将p转换为&amp;int类型的指针</p>
<h3 id="unsafe__sizeof">unsafe__Sizeof</h3>
<p>unsafe__Sizeof 接收一个参数，参数必须是当前<a
href="#作用域">作用域</a>拥有的类型T</p>
<p>语义是返回类型T的占内存长度，单位字节</p>
<h3 id="mallocsize">mallocSize</h3>
<p>mallocSize
接收一个参数，返回一个unsafe__Pointer类型的指针，第一个参数必须是表达整数的表达式</p>
<p>语义是将分配一段长度为第一个参数的连续内存，并返回这段内存的首地址，作为一个unsafe__Pointer类型的指针返回</p>
<hr />
<h2 id="包">包</h2>
<p>包由同一目录的数个源文件组成，是管理代码的基本单位</p>
<h3 id="包声明">包声明</h3>
<p>包声明的语法是 package x，x是标识符，称为包名</p>
<p>语义是声明源文件属于x包 包声明必须出现在源文件的第一行
同一目录的源文件必须属于同一个包 包名不能是unsafe</p>
<p>包名除了main,其他必须等于目录名 示例：目录绝对路径=E:\ufile\src\rg
则包名如果不是main必须等于rg</p>
<p>包名必须符合下列规则：</p>
<ul>
<li>没有换行符</li>
<li>没有双引号</li>
<li>没有空格</li>
</ul>
<h3 id="包导入路径">包导入路径</h3>
<p>对于包p，import能导入包p的字符串称为包导入路径</p>
<p>如果相对当前目录存在包p，则包导入路径可以是 "./p" 或
"../p"，这种称为相对包导入路径</p>
<p>相对包导入路径的语法是：开头是"./或"../且是一个字符串</p>
<p>远程包导入路径是形如"https://gitee.com/u-language/u-language.git"的路径，语法是一个字符串，字符串表示git仓库的https地址</p>
<h3 id="包导入">包导入</h3>
<p>包导入的语法是 import {换行 包导入列表}</p>
<p>包导入列表语法是递归定义的，语法形式为： 包导入路径[换行
包导入路径]</p>
<p>下个示例是语法正确的：</p>
<p>import {<br> "./x"<br> "./y"<br> }</p>
<p>下个示例是语法错误的：</p>
<p>import {"./x"}</p>
<p>包导入之后，如果导入x包，可以通过x.y访问x包的导出标识符</p>
<h3 id="包的标识符导出">包的标识符导出</h3>
<p>一个包中符合下列规则的标识符是导出的，可以被其他包使用</p>
<ul>
<li>如果开头是英文字母，并且是大写的英文字母</li>
<li>如果开头不是英文字母，并且开头不是_</li>
</ul>
<h3 id="包依赖">包依赖</h3>
<p>如果包x导入包y,则包x依赖包y</p>
<hr />
<h2 id="初始化">初始化</h2>
<h3 id="初始化函数">初始化函数</h3>
<p>初始化函数是一个命名为init的函数
初始化函数不能被以init()的形式调用</p>
<p><strong>初始化函数的执行结束在main()函数的执行开始之前</strong></p>
<h3 id="全局变量初始化">全局变量初始化</h3>
<p>全局变量在声明时的赋值称为全局变量初始化</p>
<p>全局变量初始化由变量声明时的行数决定，行数越小，全局变量初始化越早</p>
<p>对于n &lt; m ,第n行全局变量的初始化在第m行全局变量的初始化之前</p>
<p>全局变量初始化完成在init函数执行之前</p>
<p><strong>在同一个包不同文件行数相同的全局变量初始化顺序是未定义的</strong></p>
<h3 id="包初始化">包初始化</h3>
<p>如果包x导入包y，y的init函数执行结束在x的init函数执行开始之前</p>
<p>如果多个包导入同一个包x，包x的init函数只被调用一次</p>
<p>如果被一个包依赖的两个包之间没有依赖关系，那么这两个包的init函数运行顺序未定义。</p>
<p>举例：包a依赖包b和包c，包b和包c之间互不依赖，那么包b和包c的init函数以怎样的顺序运行未定义。</p>
<hr />
<h2 id="内存">内存</h2>
<h3 id="栈与堆">栈与堆</h3>
<p>栈是以后进先出管理的内存，堆是可动态分配的内存区域统称</p>
<h3 id="函数栈">函数栈</h3>
<p>一个函数有一个专属于这个函数的栈，这个栈称为函数栈</p>
<p><strong>在函数return执行后访问函数栈内存的行为未定义</strong></p>
<p>局部变量分配在函数栈内</p>
<h3 id="手动使用堆">手动使用堆</h3>
<p><a href="#malloc">malloc</a>和<a
href="#mallocsize">mallocSize</a>内置函数在堆中分配内存，并返回分配内存首地址的指针</p>
<p><strong><a
href="#free">free</a>释放在堆中分配内存，如果内存不是在堆中分配，行为未定义。</strong></p>
<h3 id="自动释放块">自动释放块</h3>
<p>自动释放块实现<strong>释放自动</strong>的堆使用</p>
<p>自动释放块的声明格式是</p>
<p>autofree N {</p>
<p>}</p>
<p>N必须是一个表达整数的表达式，N表示预先准备N个字节的连续内存等待分配。</p>
<p>自动释放块的语义是将在内部<strong>由<a href="#malloc">malloc</a>或<a
href="#mallocsize">maloocSize</a>分配的内存将在代码块执行完毕后释放</strong></p>
<p>在自动释放块内嵌套自动释放块，被嵌套的称为子自动释放块，子自动释放块内的<a
href="#malloc">malloc</a>或<a
href="#mallocsize">maloocSize</a>分配的内存将<strong>在子自动释放块的代码块执行完毕后释放</strong></p>
<p><strong>在自动释放块中或自动释放块中调用的函数或方法中使用<a
href="#free">free</a>的行为未定义。</strong></p>
<p>如果 N是负数，将视为0</p>
<h2 id="泛型">泛型</h2>
<h3 id="类型参数">类型参数</h3>
<p>类型参数的语法形式是： T
C，T是类型占位符，C是约束，T必须是一个标识符，C必须是接口类型。</p>
<h3 id="类型参数列表">类型参数列表</h3>
<p>类型参数列表的语法是递归定义的，语法形式是：左中括号 类型参数
[,类型参数] 右中括号</p>
<p>可选的 ,类型参数
可以有多个，每当类型参数多一个，类型参数列表的长度+1，这个类型参数的下标为类型参数列表之前的长度</p>
<p>例如 下列两个是符合语法的类型参数列表：</p>
<p>[T any] 类型参数列表的长度是1，T any 的下标是0</p>
<p>[T any,S any] 类型参数列表的长度是2 T any 的下标是0 S any
的下标是1</p>
<h3 id="泛型类型">泛型类型</h3>
<p>有<a href="#类型参数列表">泛型参数列表</a>的结构体是泛型结构体 有<a
href="#类型参数列表">泛型参数列表</a>的函数是泛型函数 有<a
href="#类型参数列表">泛型参数列表</a>的方法是泛型方法</p>
<h3 id="实例化列表">实例化列表</h3>
<p>类型参数列表的语法是递归定义的，语法形式是：左中括号 类型名 [,类型名]
右中括号</p>
<p>每当类型名多一个，实例化列表的长度+1，这个类型名的下标为实例化列表之前的长度</p>
<p>可选的 ,类型名可以有多个</p>
<p>实例化列表的类型名时所有类型名用_分隔进行拼接</p>
<p>例如下列符合语法的实例化列表:</p>
<p>[int] 类型名是 int</p>
<p>[int,float] 类型名是 int_float</p>
<h3 id="泛型类型实例化">泛型类型实例化</h3>
<p>泛型类型实例化的语法形式是T实例化列表。</p>
<p>泛型类型实例化按下列步骤进行：</p>
<ol type="1">
<li>检查T的类型的类型参数列表是否和实例化列表长度相等，如果不相等，实例化失败</li>
<li>检查实例化列表的类型名是否满足类型参数列表相同下标的类型参数的约束，如果不满足，实例化失败</li>
<li>将泛型类型中的类型参数替换为实例化类别相同下标的类型名，并去除类型参数列表</li>
<li>给实例化出的类型赋予T的类型名+下划线(_)+实例化列表的类型名</li>
</ol>
<p>例如下列代码</p>
<pre><code>package main

struct s[T any,S any] {
    p &amp;T
    p2 &amp;S
}

func News[T any,S any](t &amp;T , s &amp;S)s[T,S] {
    var ret s[T,S]
    ret.p = t
    ret.p2 = s
    return value[s[T,S]](ret)
}

method print[T any,S any](p s[T,S]){
    printf(&quot;%lld %g&quot; , @(p.p), @(p.p2))
}

func main(){
    var t s[int,float]
    var i int = 1
    var f float = 1.2
    t = News[int,float](&amp;i , &amp;f)
    t.print()
}

func value[T any](v T)T {
    return v
}</code></pre>
<p>以变量t为例，泛型示例化的步骤如下</p>
<ol type="1">
<li>先检查类型s的类型参数列表和s[int,float]的长度是否相等，如果不相等，实例化失败</li>
<li>检查int是否满足类型参数列表相同下标的T
any中的约束，检查float是否满足类型参数列表相同下标的S
any中的约束，如果不满足，实例化失败</li>
<li>将泛型类型中的类型参数替换为实例化类别相同下标的类型名，并去除类型参数列表</li>
<li>给实例化出的类型赋予T的类型名(s)+下划线(_)+实例化列表的类型名(int_float)</li>
</ol>
<p>执行第3步和第4步后，</p>
<pre><code>struct s[T any,S any] {
    p &amp;T
    p2 &amp;S
}</code></pre>
<p>实例化出</p>
<pre><code>struct s_int_float {
    p &amp;int
    p2 &amp;float
}</code></pre>
